
/*							*/
/*  Indexed Sequential Access Method			*/
/*  Relational Database Systems, Inc.			*/
/*							*/
/*		Proprietary Data			*/
/*    This document contains proprietary information	*/
/* and trade secrets which are the property of		*/
/* Relational Database Systems, Inc. (RDSI). This	*/
/* document is submitted to recipient in confidence.	*/
/* The information contained herein may not be used,	*/
/* copied or disclosed in whole or in part except as	*/
/* permitted by written agreement signed by an officer	*/
/* of RDSI.						*/
/*							*/

/*
 * isam open and close routines
 *
 * Relational Database Systems, Inc.
 * Roy Harrington	November 4, 1981
 *
 *  06-07-83  RVH	V104 -- added kernel modifications
 */

#include "isdec.c"

/*
 * open isam file
 */
 
isopen(filename, mode)
char *filename;		/* V104 - NOTE: for kernel this is array of ptrs */
register int mode;
{
	register int lockmode;
	register int isfd;

#ifndef ISKERNEL	/* V104 */
	if (ckfilname(filename)) return(-1);
#endif

	if ((isfd = allocopen()) < 0)		/* allocate open struct	*/
	    return(-1);

	openp->o_mode = mode & IOMASK;
	lockmode = mode & LOCKMASK;
	switch (lockmode)			/* check for legal mode	*/
	    {
	    case OLD_AUTO:
		lockmode = ISAUTOLOCK; break;
	    case OLD_EXCL:
		lockmode = ISEXCLLOCK; break;
	    case ISAUTOLOCK:
	    case ISMANULOCK:
	    case ISEXCLLOCK:
		break;
	    default:
		iserrno = EBADARG;
		goto openerr;
	    }

	switch (openp->o_mode)
	    {
	    case ISINPUT:
	    case ISOUTPUT:
	    case ISINOUT:
		break;
	    default:
		iserrno = EBADARG;
		goto openerr;
	    }
						/* allocate file struct	*/
	filep = openp->o_filep = allocfile(filename, openp->o_mode);
	if (filep == NULL)
	    goto openerr;

	filep->f_idxsize = NODESIZE-1;
	if (isenter(isfd, openp->o_mode))
	    goto openerr;

	if (lkopenlock(lockmode))
	    goto opener2;

	openp->o_mode += lockmode;		/* add in lock mode now	*/
	filep->f_idxsize = ld2(dictp->d_idxsize);
	filep->f_datsize = ld2(dictp->d_recsize);
#ifdef MPM86
	filep->f_datsize |= 0177;		/* make 128 byte records*/
#endif /* MPM86 */

	if ((ld2(dictp->d_magic) & 0177777) != ISMAGIC ||
#ifdef VARIDXSIZ
	    filep->f_idxsize < 127 || filep->f_idxsize >= NODESIZE ||
	    (filep->f_idxsize & (filep->f_idxsize+1)) != 0 ||
						/* must be power of 2	*/
#else
	    filep->f_idxsize != NODESIZE-1 ||
#endif
	    ld1(dictp->d_dflag) != 2 ||
	    kysearch(&openp->o_curkey, 1) < 0)
	    {					/* illegal ISAM file	*/
	    iserrno = EBADFILE;
	    }
	else kposition(temprecord, 0, ISFIRST);

	if (iserrno == 0)
	    {
	    VOID isexit();
	    return(isfd);			/* return is file desc	*/
	    }
	VOID lkopenlock(UNLOCK);
opener2:
	VOID isexit();
openerr:
	if (openp->o_flags & OSLOCK)		/* semaphore lock on ?	*/
	    VOID lksemaphore(UNLOCK);		/* yes, release it	*/
	freeopen(openp);
	return(-1);				/* return error	code	*/
}

/*
 * cleanup routine, closes all isam files
 */

iscleanup()
{
	register struct open *op;
	register int i;

	for (i=0; i<nopens; i++)
	    {
	    op = opens[i];
	    if (op != NULL && op->o_flags & OBUSY)
		VOID isclose(i);
	    }
	return(0);
}

/*
 * close isam file
 */

isclose(isfd)
int isfd;
{
	register int cc;

	if (isenter(isfd, -1) == -1) return(-1);
	if (! (openp->o_flags & OSLOCK))	/* force semaphore lock	*/
	    VOID lksemaphore(LOCKUNCOND);
	VOID lkfile(UNLOCK);
	VOID lkopenlock(UNLOCK);
	openp->o_flags &= ~OSLOCK;		/* save semaphore lock	*/
	cc = isexit();
	bfflush(filep);
	VOID lksemaphore(UNLOCK);
	freeopen(openp);
	return(cc);
}

/*
 * release locks on isam file
 */

isrelease(isfd)
int isfd;
{
	if (isenter(isfd, ISINPUT) == -1) return(-1);
	VOID lkfile(UNLOCK);
	return(isexit());
}

#ifndef ISKERNEL	/* V104 */
/*
 * flush all buffers for isam file
 */

isflush(isfd)
int isfd;
{
	if (isenter(isfd, ISOUTPUT) == -1) return(-1);
	VOID isexit();
	bfflush(filep);
	return(iserrno? -1: 0);
}
#endif  /* ISKERNEL */

/*
 * enter into isam routine
 */

STATIC int isenter(isfd, mode)
register int isfd;
register int mode;
{
	long ver;

	iserrno = iserrio = 0;			/* clear error codes	*/
	if (isfd < 0 || isfd >= nopens)
	    goto starterr;
	openp = opens[isfd];			/* point to open file	*/
	if (openp == NULL || ! (openp->o_flags & OBUSY))
	    goto starterr;			/* file open ?		*/
	filep = openp->o_filep;
	if (((mode+1) & (openp->o_mode+1)) != (mode+1))
	    goto starterr;
	if (! (openp->o_mode & ISEXCLLOCK))
	    if (lksemaphore(LOCKUNCOND))	/* lock isam file	*/
		return(-1);

	filep->f_flags &= ~FMODF;
	openp->o_flags &= ~ODUPL;
	filep->f_dicbp = bfread(1L);		/* read dictionary	*/
	if (filep->f_dicbp == NULL)
	    {
	    if (! (openp->o_mode & ISEXCLLOCK))
		VOID lksemaphore(UNLOCK);
	    return(-1);
	    }
	dictp = filep->f_dicbp->bf_un.bf_dict;
	treelev = openp->o_trlev;		/* restore tree globals	*/
	treeleaf = openp->o_trleaf;
	treeflags = openp->o_trflags;

	ver = ld4(dictp->d_transaction);
	if (openp->o_version != ver)		/* versions match ?	*/
	    {
	    openp->o_version = ver;		/* no, ignor all saved	*/
	    if (filep->f_version != ver)
		{
		filep->f_version = ver;
		bfignor(filep);			/* ignor buffers	*/
		}
	    treelev = -1;
	    }
	if (treelev >= 0)			/* init treeitem	*/
	    itcopy(&openp->o_curitem, &treeitem, &openp->o_curkey);

	if (openp->o_mode & ISAUTOLOCK)
	    VOID lkfile(UNLOCK);		/* unlock records	*/

	return(0);

starterr:
	iserrno = ENOTOPEN;			/* file not open	*/
	return(-1);
}

/*
 * exit from isam routine
 */

STATIC int isexit()
{
	openp->o_trlev = treelev;		/* save tree globals	*/
	openp->o_trleaf = treeleaf;
	openp->o_trflags = treeflags;

	if (filep->f_flags & FMODF)		/* file modified ?	*/
	    {					/* yes			*/
	    filep->f_flags &= ~FMODF;		/* clear modified bit	*/
	    openp->o_version = ++filep->f_version;
	    st4(openp->o_version, dictp->d_transaction);
						/* inc version number	*/
	    filep->f_dicbp->bf_flags |= BFMODF;
	    }
	bfrelease(filep->f_dicbp);		/* release dict buffer	*/

#ifndef MEMLOCK
#ifndef NOLOCK
#ifndef ISKERNEL
	if (! (openp->o_mode & ISEXCLLOCK))	/* if not exclusive	*/
	    {
	    bfflush(filep);			/* flush node buffers	*/
	    filep->f_dicbp->bf_flags &= ~BFDONE; /* must reread dictionary */
	    }
#endif
#endif
#endif

	switch(iserrno)				/* set status flags	*/
	    {
	    case 0:
		isstat1 = '0';
		isstat2 = (openp->o_flags & ODUPL) ? '2' : '0';
		break;
	    case EDUPL:
		isstat1 = '2'; isstat2 = '2'; break;
	    case EENDFILE:
		isstat1 = '1'; isstat2 = '0'; break;
	    case ENOREC:
		isstat1 = '2'; isstat2 = '3'; break;
	    case ENOCURR:
		isstat1 = '2'; isstat2 = '1'; break;
	/*  case ENOTOPEN:
	    case EBADARG:
	    case EBADKEY:
	    case ETOOMANY:
	    case EBADFILE:
	    case ENOTEXCL:
	    case ELOCKED:
	    case EKEXISTS:
	    case EPRIMKEY:
	*/
	    default:
		isstat1 = '9'; isstat2 = '0'; break;
	    }

	if (openp->o_flags & OSLOCK)		/* semaphore set ?	*/
	    VOID lksemaphore(UNLOCK);		/* yes, release it	*/

	return(iserrno? -1: 0);
}

/*
 * return unique id
 */

isuniqueid(isfd, uniqid)
int isfd;
long *uniqid;
{
	long id;

	if (isenter(isfd, -1) == -1) return(-1);

	id = ld4(dictp->d_uniqid);		/* get unique id	*/
	*uniqid = id++;
	st4(id, dictp->d_uniqid);		/* update unique id	*/
	filep->f_dicbp->bf_flags |= BFMODF;

	return(isexit());
}

/*
 * set unique id
 */

issetunique(isfd, uniqid)
int isfd;
long uniqid;
{
	if (isenter(isfd, -1) == -1) return(-1);

	st4(uniqid, dictp->d_uniqid);		/* store new unique id	*/
	filep->f_dicbp->bf_flags |= BFMODF;

	return(isexit());
}

/*
 * return index info
 */

isindexinfo(isfd, keyd, mode)
int isfd;
struct keydesc *keyd;
register int mode;
{
	union
	    {
	    struct keydesc *key;
	    struct dictinfo *dic;
	    } info;
	register struct buff *bp;
	long nrecs, node;

	if (isenter(isfd, -1) == -1) return(-1);

	info.key = keyd;
	if (mode == 0)
	    {
	    info.dic->di_nkeys   = ld2(dictp->d_nkeys);
	    info.dic->di_recsize = ld2(dictp->d_recsize);
	    info.dic->di_idxsize = ld2(dictp->d_idxsize);
	    nrecs = ld4(dictp->d_nextdata);	/* number of records	*/
	    node  = ld4(dictp->d_freedata);
	    while (node != 0)			/* subtract free ones	*/
		{
		bp = bfread(node);
		if (bp == NULL) break;
		nrecs -= (bp->bf_used-6) / 4;
		node = ld4(bp->bf_un.bf_free->fn_next);
		bfrelease(bp);
		}
	    info.dic->di_nrecords = nrecs;
	    }
	else
	    {
	    if (kysearch(info.key, mode) < 0)
		iserrno = EBADKEY;
	    }
	
	return(isexit());
}

